package com.lw.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.lw.common.enums.GlobalTypeEnum;
import com.lw.common.utils.StrUtils;
import com.lw.entity.TbUser;
import com.lw.entity.TbUserNotice;
import com.lw.service.TbUserNoticeService;
import com.lw.service.TbUserService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.lw.entity.TbNotice;
import com.lw.mapper.TbNoticeMapper;
import com.lw.service.TbNoticeService;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static com.lw.entity.table.TbNoticeTableDef.TB_NOTICE;
import static com.lw.entity.table.TbUserTableDef.TB_USER;

/**
 * 通知公告表 服务层实现。
 *
 * @author lw
 * @since 2025年05月15日 00:14:58
 */
@Service
@RequiredArgsConstructor
public class TbNoticeServiceImpl extends ServiceImpl<TbNoticeMapper, TbNotice> implements TbNoticeService {

    @Resource
    private TbUserNoticeService tbUserNoticeService;

    @Resource
    private TbUserService tbUseService;

    @Resource
    UserOnlineService userOnlineService;

    @Resource
    SimpMessagingTemplate messagingTemplate;



    @Override
    public Page<TbNotice> getNoticePage(TbNotice tbNotice) {
        Page<TbNotice> page = new Page<>();
        page.setPageNumber(tbNotice.getPageNum());
        page.setPageSize(tbNotice.getPageSize());
        QueryChain<TbNotice> publisherName = queryChain().select(TB_NOTICE.ALL_COLUMNS, TB_USER.NICKNAME.as("publisherName"))
                .from(TB_NOTICE).leftJoin(TB_USER).on(TB_NOTICE.PUBLISHER_ID.eq(TB_USER.ID))
                .orderBy(TB_NOTICE.CREATE_TIME.desc());
        //标题查询条件
        if (StrUtils.hasLength(tbNotice.getTitle())) {
            publisherName.where(TB_NOTICE.TITLE.like("%" + tbNotice.getTitle() + "%"));
        }
        //状态查询条件
        if (tbNotice.getPublishStatus() != null) {
            publisherName.where(TB_NOTICE.PUBLISH_STATUS.eq(tbNotice.getPublishStatus()));
        }
        return publisherName.page(page);
    }

    @Override
    public Boolean saveNotice(TbNotice tbNotice) {
        if (tbNotice.getTargetType().equals(GlobalTypeEnum.NOTICE_SPECIFIED.getValue())) {
            String[] targetUserIds = tbNotice.getTargetUserIds().split(",");    // 分割目标用户ID
            if (targetUserIds.length == 0) {
                throw new RuntimeException("目标用户ID不能为空");
            }
        }
        tbNotice.setCreateBy(StpUtil.getLoginIdAsLong());
        return save(tbNotice);
    }

    @Override
    public Boolean updateNotice(TbNotice tbNotice) {
        if (tbNotice.getTargetType().equals(GlobalTypeEnum.NOTICE_SPECIFIED.getValue())) {
            String[] targetUserIds = tbNotice.getTargetUserIds().split(",");    // 分割目标用户ID
            if (targetUserIds.length == 0) {
                throw new RuntimeException("目标用户ID不能为空");
            }
        }
        tbNotice.setCreateBy(StpUtil.getLoginIdAsLong());
        return updateById(tbNotice);
    }

    @Override
    public Boolean deleteNotice(String ids) {
        if (StrUtils.isEmpty(ids)) {
            throw new RuntimeException("主键不能为空");
        }
        String[] idArray = ids.split(",");
        List<Long> idsList = Arrays.stream(idArray).map(Long::parseLong).toList();
        boolean result = removeByIds(idsList);
        if (result) {
            //删除通知表成功后删除用户通知记录
            tbUserNoticeService.remove(new QueryWrapper().in(TbUserNotice::getUserId, idsList));
        }
        return result;
    }

    //获取通知信息
    @Override
    public TbNotice getNoticeInfo(Long id) {
        TbNotice tbNotice = getById(id);

        //将未读设置已读
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq(TbUserNotice::getNoticeId, id);
        queryWrapper.eq(TbUserNotice::getIsRead, GlobalTypeEnum.NOTICE_NO_READ.getValue());
        queryWrapper.eq(TbUserNotice::getUserId, StpUtil.getLoginIdAsLong());
        TbUserNotice tbUserNotice = new TbUserNotice();
        tbUserNotice.setIsRead(GlobalTypeEnum.NOTICE_READ.getValue());
        tbUserNoticeService.update(tbUserNotice, queryWrapper);

        return tbNotice;
    }

    @Override
    @Transactional
    public Boolean publishNotice(Long id) {
        TbNotice tbNotice = getById(id);
        if (tbNotice == null) {
            throw new RuntimeException("通知公告不存在");
        }
        //判断是否已发布
        if (tbNotice.getPublishStatus().equals(GlobalTypeEnum.NOTICE_PUBLISHED.getValue())) {
            throw new RuntimeException("通知公告已发布");   //已发布
        }
        Integer targetType = tbNotice.getTargetType();
        String targetUserIds = tbNotice.getTargetUserIds();
        if (targetType.equals(GlobalTypeEnum.NOTICE_SPECIFIED.getValue()) && StrUtils.isEmpty(targetUserIds)) {
            throw new RuntimeException("指定用户ID不能为空");
        }
        tbNotice.setPublishStatus(GlobalTypeEnum.NOTICE_PUBLISHED.getValue());
        tbNotice.setPublisherId(StpUtil.getLoginIdAsLong());
        tbNotice.setPublishTime(LocalDateTime.now());
        boolean publishResult = this.updateById(tbNotice);
        if (publishResult) {
            // 发布通知公告的同时，删除该通告之前的用户通知数据，因为可能是重新发布
            tbUserNoticeService.remove(new QueryWrapper().eq(TbUserNotice::getNoticeId, id));
            // 发布通知公告的同时，添加用户通知数据
            List<String> targetUserIdList = null;
            if (targetType.equals(GlobalTypeEnum.NOTICE_SPECIFIED.getValue())) {
                targetUserIdList = Arrays.asList(targetUserIds.split(","));
            }
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.in(TbUser::getId, targetUserIdList, targetType.equals(GlobalTypeEnum.NOTICE_SPECIFIED.getValue()));
            List<TbUser> targetUserList = tbUseService.list(queryWrapper);
            List<TbUserNotice> userNoticeList = targetUserList.stream().map(user -> {
                TbUserNotice tbUserNotice = new TbUserNotice();
                tbUserNotice.setNoticeId(id);
                tbUserNotice.setUserId(user.getId());
                tbUserNotice.setIsRead(GlobalTypeEnum.NOTICE_NO_READ.getValue());
                return tbUserNotice;
            }).toList();
            if (CollectionUtil.isNotEmpty(userNoticeList)) {
                tbUserNoticeService.saveBatch(userNoticeList);
            }
            Set<String> receivers = targetUserList.stream().map(TbUser::getUsername).collect(Collectors.toSet());

            Set<String> allOnlineUsers = userOnlineService.getOnlineUsers().stream()
                    .map(UserOnlineService.UserOnlineDTO::getUsername)
                    .collect(Collectors.toSet());
            // 计算在线用户接收者
            Set<String> onlineReceivers = new HashSet<>(CollectionUtil.intersection(receivers, allOnlineUsers));

            onlineReceivers.forEach(receiver -> messagingTemplate.convertAndSendToUser(receiver, "/queue/message", tbNotice));
        }
        return publishResult;
    }


    @Override
    @Transactional
    public Boolean revoke(Long id) {
        TbNotice tbNotice = getById(id);
        if (tbNotice == null) {
            throw new RuntimeException("通知公告不存在");
        }
        //判断是否发布,未发布不能撤回
        if (!tbNotice.getPublishStatus().equals(GlobalTypeEnum.NOTICE_PUBLISHED.getValue())) {
            throw new RuntimeException("通知公告未发布或已撤回");   //已发布
        }
        tbNotice.setPublishStatus(GlobalTypeEnum.NOTICE_REVOKED.getValue());
        tbNotice.setRevokeTime(LocalDateTime.now());
        tbNotice.setUpdateBy(StpUtil.getLoginIdAsLong());
        boolean revokeResult = this.updateById(tbNotice);

        if (revokeResult) {
            // 撤回通知公告的同时，需要删除通知公告对应的用户通知状态
            tbUserNoticeService.remove(new QueryWrapper().eq(TbUserNotice::getNoticeId, id));
        }
        return revokeResult;
    }

}
